package com.gwtintegration.smartrf.client;

import com.google.gwt.core.client.JavaScriptObject;

public class JsUtils {

	@SuppressWarnings("unchecked")
	public static <T> T clone(T object) {
		return (T) __clone(object);
	}

	private static native Object __clone(Object object)
	/*-{
		var cloneCache = new Array();
		var copy = @com.gwtintegration.smartrf.client.JsUtils::__clone(Ljava/lang/Object;Lcom/google/gwt/core/client/JavaScriptObject;)(object, cloneCache);
		cloneCache.splice(0, cloneCache.length);
		return copy;
	}-*/;

	private static native Object __clone(Object object, JavaScriptObject cloneCache)
	/*-{
		// This method support cloning objects between to browser window. Because of
		// that it can not use instanceof or constructor === Type for type comparison.

		// Handle the 3 simple types, and null or undefined
		if (null == object || "object" != typeof object) {
			return object;
		}

		// Return the cached value
		if (object.__cloneCache === cloneCache
				&& object.__cloneIndex !== undefined) {
			return cloneCache[object.__cloneIndex];
		}

		// Handle Date
		if (Object.prototype.toString.call(object) === "[object Date]") {
			var copy = new Date();
			copy.setTime(object.getTime());
			return copy;
		}

		// Handle Array
		if (Object.prototype.toString.call(object) === "[object Array]") {
			var copy = object.constructor();
			for ( var i = 0, len = object.length; i < len; i++) {
				copy[i] = @com.gwtintegration.smartrf.client.JsUtils::__clone(Ljava/lang/Object;Lcom/google/gwt/core/client/JavaScriptObject;)(object[i], cloneCache);
			}
			return copy;
		}

		// Handle Object
		if (Object.prototype.toString.call(object) === "[object Object]") {

			var clazz = object.@java.lang.Object::___clazz;
			var copy = null;

			if (clazz != null) {
				var seedId = clazz.@java.lang.Class::seedId;
				var copy = new (@com.google.gwt.lang.SeedUtil::seedTable[seedId]);
			} else {
				var copy = object.constructor();
			}

			object.__cloneCache = cloneCache;
			object.__cloneIndex = cloneCache.length;
			cloneCache.push(copy);

			for ( var attr in object) {
				if (attr != '__cloneCache' && attr != '__cloneIndex'
						&& attr != '$H' && object.hasOwnProperty(attr)) {
					copy[attr] = @com.gwtintegration.smartrf.client.JsUtils::__clone(Ljava/lang/Object;Lcom/google/gwt/core/client/JavaScriptObject;)(object[attr], cloneCache);
				}
			}
			return copy;
		}

		console
				.log("WARN: Unable to clone object! Its type isn't supported. Type: "
						+ object);
		return object;
	}-*/;

	public static native void copyMissingValues(JavaScriptObject src, JavaScriptObject dest)
	/*-{
		for ( var attr in src) {
			if (src.hasOwnProperty(attr)) {

				var srcObj = src[attr];
				var destObj = dest[attr];

				if (srcObj instanceof Object && destObj instanceof Object) {
					@com.gwtintegration.smartrf.client.JsUtils::copyMissingValues(Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(srcObj, destObj);
				} else {
					dest[attr] = srcObj;
				}
			}
		}
	}-*/;

}
